﻿using System;
using System.Collections.Generic;
using Allegro.Framework;
using Allegro.MathInterface;

namespace Allegro.Mathlib
{
    public static partial class Statistics
    {
        public static double Mean(double[] x)
        {
            int n = x.Length;
            double mean = 0.0;
            for (int i = 0; i < n; i++)
            {
                mean += x[i];
            }
            mean /= n;
            return mean;
        }
        public static double Covariance(double[] x, double[] y)
        {
            double covariance;
            double exy = 0.0;
            double ex = 0.0;
            double ey = 0.0;
            if (x.Length != y.Length)
            {
                ErrorHandler.Error("Statistics.Covariance: Arguments must have same dimension");
            }
            double n = x.Length;
            for (int i = 0; i < n; i++)
            {
                ex += x[i];
                ey += y[i];
                exy += x[i] * y[i];
            }
            exy /= n;
            ex /= n;
            ey /= n;
            covariance = (exy - ex * ey);
            return covariance;
        }
        /// <summary>
        /// Compute covariance given expectation values for ex for x and ey for y
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="ex">Expectation value for x</param>
        /// <param name="ey">Expectation value for y</param>
        /// <returns></returns>
        public static double Covariance(double[] x, double[] y, double ex, double ey)
        {
            double covariance;
            double exy = 0.0;
            if (x.Length != y.Length)
            {
                ErrorHandler.Error("Statistics.Covariance: Arguments must have same dimension");
            }
            double n = x.Length;
            for (int i = 0; i < n; i++)
            {
                exy += x[i] * y[i];
            }
            exy /= n;
            covariance = (exy - ex * ey);
            return covariance;
        }
        /// <summary>
        /// Variance of vector x
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static double Variance(double[] x)
        {
            return Covariance(x, x);
        }

        /// <summary>
        /// Variance of vector given expectation value ex
        /// </summary>
        /// <param name="x"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static double Variance(double[] x, double ex)
        {
            return Covariance(x, x, ex, ex);
        }
        /// <summary>
        /// Correlation of x and y. The correlation factor is between -1 and 1.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static double Correlation(double[] x, double[] y)
        {
            double covariance = Covariance(x, y);
            double xvar = Variance(x);
            double yvar = Variance(y);
            double correlation = covariance/(Math.Sqrt(xvar*yvar));
            return correlation;
        }

        /// <summary>
        /// Compute the chi-square of two samples x and y with corresponding standard dev. sigma
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="sigma"></param>
        /// <returns></returns>
        public static double ChiSquare(double[] x, double[] y, double[] sigma)
        {
            int l = x.Length;
            double chi2 = 0.0;
            for (int i = 0; i < l; i++)
            {
                double diff = (y[i] - x[i]) / sigma[i];
                chi2 += diff * diff;
            }
            return chi2;
        }
    }
}
